package com.n5x.common.util;

import org.apache.shiro.codec.Hex;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.crypto.BlowfishCipherService;
import org.apache.shiro.crypto.DefaultBlockCipherService;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.crypto.hash.HashRequest;

import java.security.Key;

public class CipherHashUtil {

    /**
     * 初始化Aes加密算法(支持解密，解密时需要加密时生成的动态key)
     *
     * @return 加密算法内部类
     */
    public static CipherHashUtil.CipherService initAesCipherService() {
        return new CipherHashUtil.CipherService().initAesCipherService();
    }

    /**
     * 初始化Blowfish加密算法(支持解密，解密时需要加密时生成的动态key)
     *
     * @return 加密算法内部类
     */
    public static CipherHashUtil.CipherService initBlowfishCipherService() {
        return new CipherHashUtil.CipherService().initBlowfishCipherService();
    }

    /**
     * 初始化散列算法(不支付解密，可添加salt)
     *
     * @param source 加密对象
     * @param salt   盐
     * @return 散列算法内部类
     */
    public static CipherHashUtil.HashService initHashService(Object source, String salt) {
        return new CipherHashUtil.HashService(source, salt);
    }

    public static class CipherService {
        /**
         * key
         */
        private Key keyBytes;
        /**
         * 分组加密
         */
        private DefaultBlockCipherService cipherService;

        /**
         * 初始化Blowfish加密算法
         *
         * @return 加密算法对象
         */
        public CipherService initBlowfishCipherService() {
            this.cipherService = new BlowfishCipherService();
            this.keyBytes = cipherService.generateNewKey();
            return this;
        }

        /**
         * 初始化Aes加密算法
         *
         * @return 加密算法对象
         */
        public CipherService initAesCipherService() {
            this.cipherService = new AesCipherService();
            this.keyBytes = cipherService.generateNewKey();
            return this;
        }

        /**
         * 加密
         *
         * @param encrypt 需要加密码字符
         * @return 加密后字符
         */
        public String encrypt(String encrypt) {
            return this.cipherService.encrypt(encrypt.getBytes(), this.keyBytes.getEncoded()).toHex();
        }

        /**
         * 解密
         *
         * @param decrypt 解密
         * @param bytes   解密key字节数组
         * @return 解密后字符
         */
        public String decrypt(String decrypt, byte[] bytes) {
            return new String(this.cipherService.decrypt(Hex.decode(decrypt), bytes).getBytes());
        }

        /**
         * 获取解密key字节数组
         *
         * @return 解密key字节数组
         */
        public byte[] getKeyBytes() {
            return this.keyBytes.getEncoded();
        }
    }

    /**
     * 散列算法
     */
    public static class HashService {
        /**
         * SHA-256 算法
         */
        public final String DEFAULT_HASH_ALGORITHM = "SHA-256";
        /**
         * 迭代次数
         */
        public final int DEFAULT_HASH_ITERATIONS = 100;
        /**
         * 散列算法
         */
        private DefaultHashService hashService;
        /**
         * 提供各种加密需要的参数专门类
         */
        private HashRequest.Builder builder = new HashRequest.Builder();

        public HashService(Object source, String salt) {
            hashService = new DefaultHashService();
            builder.setSource(source);
            builder.setSalt(salt);
            builder.setAlgorithmName(DEFAULT_HASH_ALGORITHM);
            builder.setIterations(DEFAULT_HASH_ITERATIONS);
        }

        /**
         * 重置算法
         *
         * @param algorithmName 算法名称
         * @return 散列算法对象
         */
        public CipherHashUtil.HashService algorithmName(String algorithmName) {
            builder.setAlgorithmName(algorithmName);
            return this;
        }

        /**
         * 重置选代次数
         *
         * @param iterations 选代次数
         * @return 散列算法对象
         */
        public CipherHashUtil.HashService iterations(int iterations) {
            builder.setIterations(iterations);
            return this;
        }

        /**
         * 运算加密
         *
         * @return 加密后字符
         */
        public String computeHash() {
            return hashService.computeHash(builder.build()).toHex();
        }
    }
}
